﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MaterialSkin.Controls
{
    [DefaultEvent("Scroll")]
    [DefaultProperty("Value")]
    public class MaterialScrollBar2 : MaterialScrollBar
    {

        //top and bottom or left and right button side margin, 
        //not large than width /2 or height/2
        private const int MARGIN = 0;
        //pixel bias,just adjust to be center
        private const float BIAS_TOP_BUTTON = 0.8f;
        private const float BIAS_BOTTOM_BUTTON = 0.5f;
        //
        private int scrollBarButtonWidth = SCROLLBAR_DEFAULT_SIZE;
        private PointF[] scrollBarTopButtonTrangle = new PointF[] { PointF.Empty, PointF.Empty, PointF.Empty };
        private PointF[] scrollBarBottomButtonTrangle = new PointF[] { PointF.Empty, PointF.Empty , PointF.Empty };
        //
        private Rectangle topButtonRectangle = Rectangle.Empty;
        private Rectangle bottomButtonRectangle = Rectangle.Empty;
        private bool isTopButtonHovered = false;
        private bool isBottomButtonHovered = false;
        //
        private bool topButtonClicked = false;
        private bool bottomButtonClicked = false;
        //
        public MaterialScrollBar2()
            : base()
        {

        }

        public MaterialScrollBar2(MaterialScrollOrientation orientation)
            : this()
        {
            Orientation = orientation;
        }

        public MaterialScrollBar2(MaterialScrollOrientation orientation, int width)
            : this(orientation)
        {
            Width = width;
        }


        protected override void SetupScrollBar()
        {
            
            if (inUpdate) return;

            if (Orientation == MaterialScrollOrientation.Vertical)
            {
                thumbWidth = Width > 0 ? Width : 10;
                scrollBarButtonWidth = thumbWidth;

                thumbHeight = GetThumbSize();

                clickedBarRectangle = new Rectangle(ClientRectangle.X, ClientRectangle.Y + scrollBarButtonWidth,
                                                    ClientRectangle.Width, ClientRectangle.Height - 2 * scrollBarButtonWidth);
                clickedBarRectangle.Inflate(-1, -1);

                thumbRectangle = new Rectangle(ClientRectangle.X, ClientRectangle.Y + scrollBarButtonWidth, thumbWidth, thumbHeight);

                thumbPosition = thumbRectangle.Height / 2;
                thumbBottomLimitBottom = ClientRectangle.Bottom - scrollBarButtonWidth;
                thumbBottomLimitTop = thumbBottomLimitBottom - thumbRectangle.Height;
                thumbTopLimit = ClientRectangle.Y + scrollBarButtonWidth;
                //
                topButtonRectangle = new Rectangle(0, 0, scrollBarButtonWidth, scrollBarButtonWidth);
                bottomButtonRectangle = new Rectangle(0, Height - scrollBarButtonWidth, scrollBarButtonWidth, scrollBarButtonWidth);

            }
            else
            {
                thumbHeight = Height > 0 ? Height : 10;
                scrollBarButtonWidth = thumbHeight;
                thumbWidth = GetThumbSize();

                
                clickedBarRectangle = new Rectangle(ClientRectangle.X + scrollBarButtonWidth, ClientRectangle.Y,
                                                    ClientRectangle.Width - 2 * scrollBarButtonWidth, ClientRectangle.Height);
                clickedBarRectangle.Inflate(-1, -1);

                thumbRectangle = new Rectangle(ClientRectangle.X + scrollBarButtonWidth, ClientRectangle.Y, thumbWidth, thumbHeight);

                thumbPosition = thumbRectangle.Width / 2;
                thumbBottomLimitBottom = ClientRectangle.Right - scrollBarButtonWidth;
                thumbBottomLimitTop = thumbBottomLimitBottom - thumbRectangle.Width;
                thumbTopLimit = ClientRectangle.X + scrollBarButtonWidth;
                //
                topButtonRectangle = new Rectangle(0, 0, scrollBarButtonWidth, scrollBarButtonWidth);
                bottomButtonRectangle = new Rectangle(Width - scrollBarButtonWidth, 0 , scrollBarButtonWidth, scrollBarButtonWidth);

            }

            ChangeThumbPosition(GetThumbPosition());

            SetButtonTrangleSize();

            Refresh();
        }

        protected override int GetThumbSize()
        {
            int trackSize =
                MaterialOrientation == MaterialScrollOrientation.Vertical ?
                    Height - 2 * scrollBarButtonWidth : Width - 2 * scrollBarButtonWidth;

            if (_maximum == 0 || _largeChange == 0)
            {
                return trackSize;
            }
            //transfer the number range into the actual control size
            float newThumbSize = (_largeChange * (float)trackSize) / (_maximum - _minimum);

            return Convert.ToInt32(Math.Min(trackSize, Math.Max(newThumbSize, 10f)));
        }

        protected override int GetThumbPosition()
        {
            int pixelRange;

            if (_curValue == _minimum)
                return thumbTopLimit;
            else if (_curValue == _maximum && _bottomRightType == MaterialScrollBottomRightType.Max)
                return thumbBottomLimitTop;
            else if (_curValue >= _maximum - _largeChange + 1 && _bottomRightType == MaterialScrollBottomRightType.Not_Max)
            {
                _curValue = _maximum - _largeChange + 1;
                return thumbBottomLimitTop;
            }
            else
            {
                if (thumbHeight == 0 || thumbWidth == 0)
                {
                    return 0;
                }
                //I don't know why this line of code  is here,
                //this thumbSize is just bias?
                int thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ?
                    (thumbPosition / (Height - 2 * scrollBarButtonWidth)) / thumbHeight :
                    (thumbPosition / (Width - 2 * scrollBarButtonWidth)) / thumbWidth;

                //int thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? thumbHeight : thumbWidth;
                if (_bottomRightType == MaterialScrollBottomRightType.Max)
                {
                    thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? thumbHeight : thumbWidth;
                }

                if (Orientation == MaterialScrollOrientation.Vertical)
                {
                    pixelRange = Height - 2 * scrollBarButtonWidth - thumbSize;
                }
                else
                {
                    pixelRange = Width - 2 * scrollBarButtonWidth - thumbSize;
                }

                int realRange = _maximum - _minimum;
                float perc = 0f;

                if (realRange != 0)
                {
                    perc = (_curValue - (float)_minimum) / realRange;
                }
                //transfer value to control's pixel location
                return thumbTopLimit + Convert.ToInt32((perc * pixelRange));

                //return Math.Max(thumbTopLimit, Math.Min(thumbBottomLimitTop, Convert.ToInt32((perc * pixelRange))));
            }

        }

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="mouseLocation">client control mouse location, not screen mouse location</param>
        //protected override void ChangeTrackPosition(Point mouseLocation)
        //{
        //    trackPosition = MaterialOrientation == MaterialScrollOrientation.Vertical ? mouseLocation.Y : mouseLocation.X;
        //    if(MaterialOrientation == MaterialScrollOrientation.Vertical)
        //    {
        //        if (topButtonRectangle.Contains(mouseLocation))
        //        {
        //            trackPosition = scrollBarButtonWidth;
        //        }
        //        else if (bottomButtonRectangle.Contains(mouseLocation))
        //        {
        //            trackPosition = Height - scrollBarButtonWidth;
        //        }
        //    }
        //    else
        //    {
        //        if (topButtonRectangle.Contains(mouseLocation))
        //        {
        //            trackPosition = scrollBarButtonWidth;
        //        }
        //        else if (bottomButtonRectangle.Contains(mouseLocation))
        //        {
        //            trackPosition = Width - scrollBarButtonWidth;
        //        }
        //    }

        //}

        protected override void ProgressThumb(bool enableTimer)
        {
            int scrollOldValue = _curValue;
            ScrollEventType type = ScrollEventType.First;
            int thumbSize, thumbPos;

            if (Orientation == MaterialScrollOrientation.Vertical)
            {
                thumbPos = thumbRectangle.Y;
                thumbSize = thumbRectangle.Height;
            }
            else
            {
                thumbPos = thumbRectangle.X;
                thumbSize = thumbRectangle.Width;
            }
   
            if(bottomButtonClicked)
            {
                type = ScrollEventType.SmallIncrement;
                _curValue = GetValue(true, false);

                if (_curValue == _maximum)
                {
                    //ChangeThumbPosition(thumbBottomLimitTop);

                    type = ScrollEventType.Last;
                }
                //else
                //{
                //    //ChangeThumbPosition(Math.Min(thumbBottomLimitTop, GetThumbPosition()));

                //}
                ChangeThumbPosition(GetThumbPosition());
            }
            else if ((bottomBarClicked && (thumbPos + thumbSize) < trackPosition))
            {
                type = ScrollEventType.LargeIncrement;

                _curValue = GetValue(false, false);

                if (_curValue == _maximum)
                {
                    //ChangeThumbPosition(thumbBottomLimitTop);

                    type = ScrollEventType.Last;
                }
                //else
                //{
                //    //ChangeThumbPosition(Math.Min(thumbBottomLimitTop, GetThumbPosition()));

                //}
                ChangeThumbPosition(GetThumbPosition());
            }
            else if ((topBarClicked && thumbPos > trackPosition))
            {
                type = ScrollEventType.LargeDecrement;

                _curValue = GetValue(false, true);

                if (_curValue == _minimum)
                {
                    //ChangeThumbPosition(thumbTopLimit);

                    type = ScrollEventType.First;
                }
                //else
                //{
                //    ChangeThumbPosition(Math.Max(thumbTopLimit, GetThumbPosition()));
                //}
                ChangeThumbPosition(GetThumbPosition());
            }
            else if(topButtonClicked)
            {
                type = ScrollEventType.SmallDecrement;
                _curValue = GetValue(true, true);
                if (_curValue == _minimum)
                {
                    //ChangeThumbPosition(thumbTopLimit);

                    type = ScrollEventType.First;
                }
                //else
                //{
                //    ChangeThumbPosition(Math.Max(thumbTopLimit, GetThumbPosition()));
                //}
                ChangeThumbPosition(GetThumbPosition());
            }

            if (scrollOldValue != _curValue)
            {
                OnScroll(type, scrollOldValue, _curValue, scrollOrientation);

                Invalidate();

                if (enableTimer)
                {
                    EnableTimer();
                }
            }

        }

        protected virtual void SetButtonTrangleSize()
        {
            if (Orientation == MaterialScrollOrientation.Vertical)
            {
                //the length of triangle side x sqrt(3)/3 = the distance of the center to the vertex
                double a = (Width / 2 - MARGIN) * Math.Sqrt(3);

                scrollBarTopButtonTrangle[0] = new PointF(Width / 2 - BIAS_TOP_BUTTON, MARGIN);
                scrollBarTopButtonTrangle[1] = new PointF((float)(Width / 2 - a / 2 - BIAS_TOP_BUTTON), (float)(scrollBarTopButtonTrangle[0].Y + a * Math.Sqrt(3) / 2));
                scrollBarTopButtonTrangle[2] = new PointF((float)(Width / 2 + a / 2 - BIAS_TOP_BUTTON), (float)(scrollBarTopButtonTrangle[0].Y + a * Math.Sqrt(3) / 2));

                scrollBarBottomButtonTrangle[0] = new PointF(Width / 2 - BIAS_BOTTOM_BUTTON, Height - MARGIN);
                scrollBarBottomButtonTrangle[1] = new PointF((float)(Width / 2 - a / 2 - BIAS_BOTTOM_BUTTON), (float)(Height - (scrollBarTopButtonTrangle[0].Y + a * Math.Sqrt(3) / 2)));
                scrollBarBottomButtonTrangle[2] = new PointF((float)(Width / 2 + a / 2 - BIAS_BOTTOM_BUTTON), (float)(Height - (scrollBarTopButtonTrangle[0].Y + a * Math.Sqrt(3) / 2)));

            }
            else
            {
                //the length of triangle side x sqrt(3)/3 = the distance of the center to the vertex
                double a = (Height / 2 - MARGIN) * Math.Sqrt(3);

                scrollBarTopButtonTrangle[0] = new PointF(MARGIN, Height / 2);
                scrollBarTopButtonTrangle[1] = new PointF((float)(scrollBarTopButtonTrangle[0].X + a * Math.Sqrt(3) / 2), (float)(Height / 2 - a / 2));
                scrollBarTopButtonTrangle[2] = new PointF((float)(scrollBarTopButtonTrangle[0].X + a * Math.Sqrt(3) / 2), (float)(Height / 2 + a / 2));

                scrollBarBottomButtonTrangle[0] = new PointF(Width - MARGIN, Height / 2);
                scrollBarBottomButtonTrangle[1] = new PointF((float)(Width - (scrollBarTopButtonTrangle[0].X + a * Math.Sqrt(3) / 2)), (float)(Height / 2 - a / 2));
                scrollBarBottomButtonTrangle[2] = new PointF((float)(Width - (scrollBarTopButtonTrangle[0].X + a * Math.Sqrt(3) / 2)), (float)(Height / 2 + a / 2));
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            //paint left and right button
            DrawScrollBarButton(e.Graphics, MaterialSkinManager.Instance.CardsColor, SkinManager.SwitchOffTrackColor, _useAccentColor ? MaterialSkinManager.Instance.ColorScheme.AccentColor : MaterialSkinManager.Instance.ColorScheme.PrimaryColor);
        }

        protected virtual void DrawScrollBarButton(Graphics g, Color backColor, Color thumbColor, Color barColor)
        {

            using (SolidBrush b = new SolidBrush(isTopButtonHovered || topButtonClicked ? barColor : thumbColor))
            {
                g.FillPolygon(b, scrollBarTopButtonTrangle);
            }
            using (SolidBrush b = new SolidBrush(isBottomButtonHovered || bottomButtonClicked ? barColor : thumbColor))
            {
                g.FillPolygon(b, scrollBarBottomButtonTrangle);
            }

        }

        #region Mouse Methods

        //protected override void OnMouseWheel(MouseEventArgs e)
        //{
        //    base.OnMouseWheel(e);

        //    int v = e.Delta / 120 * (_maximum - _minimum) / _mouseWheelBarPartitions;

        //    if (Orientation == MaterialScrollOrientation.Vertical)
        //    {
        //        Value -= v;
        //    }
        //    else
        //    {
        //        Value += v;
        //    }
        //}

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {

                Point mouseLocation = e.Location;

                if (topButtonRectangle.Contains(mouseLocation))
                {
                    topButtonClicked = true;
                    bottomButtonClicked = false;

                }
                else if (bottomButtonRectangle.Contains(mouseLocation))
                {
                    topButtonClicked = false;
                    bottomButtonClicked = true;
                }


            }

            base.OnMouseDown(e);

        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (topButtonClicked)
                {
                    topButtonClicked = false;
                    StopTimer();
                    //function Invalidate() is placed inner for best, each if has a Invalidate() function, means that 
                    //no if no Invalidate() function
                    Invalidate();
                }
                else if (bottomButtonClicked)
                {
                    bottomButtonClicked = false;
                    StopTimer();
                    //function Invalidate() is placed inner for best, each if has a Invalidate() function, means that 
                    //no if no Invalidate() function
                    Invalidate();
                }
                
            }

            base.OnMouseUp(e);

        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);

            if (topButtonRectangle.Contains(this.PointToClient(Control.MousePosition)))
            {
                isTopButtonHovered = true;
                
            }
            else if(bottomButtonRectangle.Contains(this.PointToClient(Control.MousePosition)))
            {
                isBottomButtonHovered = true;
            }

            Invalidate();

        }

        protected override void OnMouseLeave(EventArgs e)
        {

            base.OnMouseLeave(e);

            isTopButtonHovered = false;
            isBottomButtonHovered = false;
            Invalidate();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            
            //((Control)(base)).OnMouseMove(e);


            if (e.Button == MouseButtons.Left)
            {
                if (thumbClicked)
                {
                    int oldScrollValue = _curValue;
                    //mouse location
                    int pos = MaterialOrientation == MaterialScrollOrientation.Vertical ? e.Location.Y : e.Location.X;
                    int thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? (pos / Height) / thumbHeight : (pos / Width) / thumbWidth;
                    if(_bottomRightType == MaterialScrollBottomRightType.Max)
                    {
                        thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? thumbHeight : thumbWidth;
                    }
                    //just pos in a small area
                    if (pos <= (thumbTopLimit + thumbPosition))
                    {
                        ChangeThumbPosition(thumbTopLimit);
                        _curValue = _minimum;
                        Invalidate();
                    }
                    else if (pos >= (thumbBottomLimitTop + thumbPosition))
                    {
                        ChangeThumbPosition(thumbBottomLimitTop);
                        _curValue = _maximum;
                        Invalidate();
                    }
                    else
                    {
                        //pos - thumbPosition = thumbRectangle's location
                        ChangeThumbPosition(pos - thumbPosition);

                        int pixelRange, thumbPos;

                        if (Orientation == MaterialScrollOrientation.Vertical)
                        {
                            pixelRange = Height - 2 * scrollBarButtonWidth - thumbSize;
                            thumbPos = thumbRectangle.Y;
                        }
                        else
                        {
                            pixelRange = Width - 2 * scrollBarButtonWidth - thumbSize;
                            thumbPos = thumbRectangle.X;
                        }

                        float perc = 0f;

                        if (pixelRange != 0)
                        {
                            perc = (thumbPos) / (float)pixelRange;
                        }

                        _curValue = Convert.ToInt32((perc * (_maximum - _minimum)) + _minimum);
                    }

                    if (oldScrollValue != _curValue)
                    {
                        OnScroll(ScrollEventType.ThumbTrack, oldScrollValue, _curValue, scrollOrientation);
                        Refresh();
                    }
                }
            }
            //else if (!ClientRectangle.Contains(e.Location))
            //{
            //    ResetScrollStatus();
            //}
            else if (e.Button == MouseButtons.None)
            {
                if (topButtonRectangle.Contains(e.Location))
                {
                    isTopButtonHovered = true;
                    Invalidate(topButtonRectangle);
                }
                else if (bottomButtonRectangle.Contains(e.Location))
                {
                    isBottomButtonHovered = true;
                    Invalidate(bottomButtonRectangle);
                }
                else if (thumbRectangle.Contains(e.Location))
                {
                    isThumbHovered = true;
                    Invalidate(thumbRectangle);
                }
                else if (ClientRectangle.Contains(e.Location))
                {
                    isThumbHovered = false;
                    isTopButtonHovered = false;
                    isBottomButtonHovered = false;
                    Invalidate();
                }
                else if (!ClientRectangle.Contains(e.Location))
                {
                    ResetScrollStatus();
                }
            }


        }

        #endregion

    }
}
